package com.lysj.order.order.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import com.lysj.admin.common.merchant.domain.WxConfigVo;
import com.lysj.admin.common.pay.domain.PayParam;
import com.lysj.admin.common.pay.domain.RefundParam;
import com.lysj.admin.utils.constant.CommonConstant;
import com.lysj.admin.utils.exception.BaseException;
import com.lysj.admin.utils.spring.foundation.base.BaseService;
import com.lysj.admin.utils.spring.foundation.pagination.PageUtil;
import com.lysj.admin.utils.spring.foundation.pagination.PageVo;
import com.lysj.admin.utils.web.ParamUtil;
import com.lysj.order.customer.vo.CusOrderDetailVo;
import com.lysj.order.customer.vo.CusOrderItmeDetailVo;
import com.lysj.order.order.cache.CusOpenidApplicationRunner;
import com.lysj.order.order.cache.CusPhoneApplicationRunner;
import com.lysj.order.order.cache.DeskNameApplicationRunner;
import com.lysj.order.order.cache.WxConfigApplicationRunner;
import com.lysj.order.order.domain.Order;
import com.lysj.order.order.domain.OrderItem;
import com.lysj.order.order.dto.OrderQueryDto;
import com.lysj.order.order.feign.*;
import com.lysj.order.order.repository.OrderRepository;
import com.lysj.order.order.util.WXPayUtil;
import com.lysj.order.order.vo.WorkBenchOrderDetailVo;
import com.lysj.order.order.vo.OrderVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.PostMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.transaction.Transactional;
import javax.annotation.Resource;
import java.io.BufferedReader;
import java.math.BigDecimal;
import java.util.*;

/**
 * @author Created by drj on 2019-03-07 16:36:33
 * @description 订单服务层:支付,支付回调,退款
 */
@Slf4j
@Service
@Transactional
public class OrderService implements BaseService<Order> {

    @Resource
    private OrderRepository orderRepository;

    @Resource
    private OrderItemService orderItemService;

    @Resource
    private HttpServletRequest request;
    @Resource
    private HttpServletResponse response;

    @Value("${wxpay.successXml}")
    public String successXml;

    @Value("${wxpay.failXml}")
    public String failXml;

    @Resource
    private WxConfigFeign wxConfigFeign;

    @Resource
    private WxPayFeign wxPayFeign;

    @Resource
    private DeskFeign deskFeign;

    @Resource
    private CustomerFeign customerFeign;


    @Override
    public OrderRepository getRepository() {
        return orderRepository;
    }

    private final static Integer DESK_FREE_STATUS = 1; //餐桌空闲状态


    /*
     * @author drj
     * @date 2019-03-13 14:33
     * @Description: 工作台点击餐桌显示订单详情
     */
    public WorkBenchOrderDetailVo workBenchOrderDetail(String deskId) {

        WorkBenchOrderDetailVo orderDetailVo = new WorkBenchOrderDetailVo();
        //查询正在开桌的订单
        Order order = orderRepository.findByDeskIdAndStatusAndDelFlag(deskId, Order.Status.PLACEORDER.getCode(), CommonConstant.NORMAL_FLAG);
        if (ParamUtil.isBlank(order)) {
            throw new BaseException("查看订单详情异常");
        }
        orderDetailVo.setOrderId(order.getId()); //订单id
        orderDetailVo.setCreateTime(order.getCreateTime()); //开桌时间
        orderDetailVo.setCusAmount(order.getCusAmount()); //用餐人数
        orderDetailVo.setStatus(order.getStatus());  //订单状态
        //查询已点菜
        Integer goodsAmount = orderItemService.getRepository().
                countByOrderIdAndStatusAndDelFlag(order.getId(), OrderItem.Status.GOODS.getCode(), CommonConstant.NORMAL_FLAG);
        orderDetailVo.setGoodsAmount(goodsAmount);
        //查询赠菜
        Integer giftAmount = orderItemService.getRepository().
                countByOrderIdAndStatusAndDelFlag(order.getId(), OrderItem.Status.GIFT.getCode(), CommonConstant.NORMAL_FLAG);
        orderDetailVo.setGiftAmount(giftAmount);
        //计算售价
        BigDecimal sellMoney = orderItemService.getRepository().summaryMoney(order.getId());
        orderDetailVo.setSellMoney(null == sellMoney ? BigDecimal.ZERO : sellMoney);
        return orderDetailVo;
    }

    /*
     * @author drj
     * @date 2019-03-13 17:07
     * @Description :后台订单列表显示
     */
    public Page<OrderVo> orderList(OrderQueryDto orderQueryDto, PageVo pageVo) {
        Pageable pageable = PageUtil.initPage(pageVo);
        Page<OrderVo> page = orderRepository.queryOrderList(pageable, orderQueryDto.getStoreId(), orderQueryDto.getOrderNumber(),DateUtil.beginOfDay(orderQueryDto.getStartCreateTime()) , DateUtil.endOfDay(orderQueryDto.getEndCreateTime()));
        for (OrderVo orderVo : page) {
            //获取手机号码
            orderVo.setPhone(CusPhoneApplicationRunner.cusPhoneCache.get(orderVo.getCustomerId(), false));
            //获取餐桌号
            orderVo.setDeskName(DeskNameApplicationRunner.deskNameCache.get(orderVo.getDeskId(), false));
            //获取点餐份数
            Integer goodsAmount = orderItemService.getRepository().
                    countByOrderIdAndStatusAndDelFlag(orderVo.getId(), OrderItem.Status.GOODS.getCode(), CommonConstant.NORMAL_FLAG);
            orderVo.setGoodsAmount(goodsAmount);
            //获取订单金额
            orderVo.setMoney(orderItemService.getRepository().summaryMoney(orderVo.getId()));
            //获取实付金额
            orderVo.setActPayMoney(null == orderVo.getActPayMoney() ? BigDecimal.ZERO : orderVo.getActPayMoney());
        }
        return page;
    }

    /*
     * @author drj
     * @date 2019-03-13 17:29
     * @Description :点击支付
     */
    public Map<String, Object> orderPay(String orderId, Integer payWay) {

        Map<String, Object> map = new HashMap<>();

        Order order = orderRepository.findOne(orderId);

        //计算售价
        BigDecimal sellMoney = orderItemService.getRepository().summaryMoney(order.getId());
        order.setDisCountMoney(BigDecimal.ZERO); //优惠金额为0元
        order.setActPayMoney(sellMoney); //实付金额为售价
        order.setPayWay(payWay); //付款方式

        //查看子订单是否有待称重菜品
        List<OrderItem> orderItemList = orderItemService.getRepository().findByOrderIdAndDelFlag(orderId, CommonConstant.NORMAL_FLAG);
        for (OrderItem orderItem : orderItemList) {
            //过滤茶座费
            if (orderItem.getStatus().equals(OrderItem.Status.TEA.getCode())) {
                continue;
            }
            if (null == orderItem.getTolPrice()) {
                throw new BaseException(orderItem.getName() + "尚未称重,请联系商户处理");
            }
        }
        //如果选择的是现金支付,直接返回
        if (Order.PayWay.CASH.getCode().equals(payWay)) {
            order.setStatus(Order.Status.SUCCESSPAY.getCode()); //将订单状态改为已支付
            orderRepository.save(order);
            //通过feign调用获改变餐桌状态为空闲状态,清空餐桌用户id
            deskFeign.initDesk(order.getDeskId());
            return map;
        }

        //获取支付配置信息
        WxConfigVo wxConfigVo = WxConfigApplicationRunner.wxConfigVoCache.get(order.getStoreId(), false);
        if (ParamUtil.isBlank(wxConfigVo)) {
            wxConfigVo = wxConfigFeign.getStoreWxpayConfig(order.getStoreId());
            WxConfigApplicationRunner.wxConfigVoCache.put(order.getStoreId(), wxConfigVo);
        }
        //获取用户openid
        String openid = CusOpenidApplicationRunner.cusOpenidCache.get(order.getCustomerId(), false);
        if (ParamUtil.isBlank(openid)) {
            openid = customerFeign.findByCustomerId(order.getCustomerId());
            CusOpenidApplicationRunner.cusOpenidCache.put(order.getCustomerId(), openid);
        }

        //初始化支付信息
        PayParam payParam = new PayParam();
        BeanUtil.copyProperties(wxConfigVo, payParam);
        payParam.setOpenid(openid);
        payParam.setOutTradeNo(order.getOrderNumber());
        payParam.setTolPrice(Integer.valueOf(sellMoney.multiply(new BigDecimal("100")).stripTrailingZeros().toPlainString()));

        //调用支付feign
        map = wxPayFeign.createOrder(payParam);
        //若返回的支付信息异常
        if ("".equals(map.get("jsPayResponse"))) {
            throw new BaseException("支付信息异常");
        }
        //保存订单信息
        orderRepository.save(order);
        return map;
    }


    /*
     * @author drj
     * @date 2019-03-14 15:07
     * @Description :支付回调
     */
    @PostMapping("/wx_order_callback")
    public void wxOrderCallback() throws Exception {
        log.info("进入支付回调");
        BufferedReader br = request.getReader();

        String str = "";
        StringBuilder sb = new StringBuilder();
        while ((str = br.readLine()) != null) {
            sb.append(str);
        }
        Map<String, String> resultMap = WXPayUtil.xmlToMap(sb.toString());
        //支付订单号
        String out_trade_no = new String(resultMap.get("out_trade_no").getBytes("ISO-8859-1"), "UTF-8");
        //回调订单号
        String trade_no = new String(resultMap.get("transaction_id").getBytes("ISO-8859-1"), "UTF-8");
        // 交易状态
        String return_code = new String(resultMap.get("return_code").getBytes("ISO-8859-1"), "UTF-8");
        //交易金额
        String total_fee = new String(resultMap.get("total_fee").getBytes("ISO-8859-1"), "UTF-8");

        Order order = orderRepository.findByOrderNumberAndDelFlag(out_trade_no, CommonConstant.NORMAL_FLAG);
        if (null == order || !order.getStatus().equals(Order.Status.PLACEORDER.getCode())) {
            response.getWriter().write(failXml);
            response.getWriter().flush();
            return;
        }
        //通过feign调用获取该商户的支付配置信息
        WxConfigVo wxConfigVo = WxConfigApplicationRunner.wxConfigVoCache.get(order.getStoreId(), false);
        //获取订单金额
        BigDecimal payMoney = order.getActPayMoney();
        //校验签名
        boolean signResutl = WXPayUtil.isSignatureValid(resultMap, "AD440BD8EB4C4C17B4AC9B49E573381A");
        if (signResutl && (new BigDecimal(total_fee).compareTo(payMoney.multiply(new BigDecimal("100")).stripTrailingZeros()) == 0) && out_trade_no.equals(order.getOrderNumber())) {        // 签名正确
            if ("SUCCESS".equals(return_code)) {
                order.setStatus(Order.Status.SUCCESSPAY.getCode());
                //支付方式暂时设定为微信支付
                orderRepository.save(order);
                //通过feign调用获改变餐桌状态为空闲状态,清空餐桌用户id
                deskFeign.initDesk(order.getDeskId());

                response.getWriter().write(successXml);
                response.getWriter().flush();
            }
        } else {
            log.error("回调发生错误，支付订单号为{}，回调订单号为{},交易金额为{}", out_trade_no, trade_no, total_fee);
            response.getWriter().write(failXml);
            response.getWriter().flush();
        }
    }

    /*
     * @author drj
     * @date 2019-04-09 14:22
     * @Description :退款操作
     */
    public String refund(String orderId, Integer status) {

        Order order = orderRepository.findOne(orderId);
        //如果选择的是拒绝退款
        if (status.equals(Order.Status.REFUNDFAIL.getCode())) {
            order.setStatus(Order.Status.REFUNDFAIL.getCode());
            orderRepository.save(order);
            return "操作成功";
        }
        //计算售价
        BigDecimal sellMoney = orderItemService.getRepository().summaryMoney(order.getId());

        RefundParam refundParam = new RefundParam();

        refundParam.setTotalFee(Integer.valueOf(sellMoney.multiply(new BigDecimal("100")).stripTrailingZeros().toPlainString())); //支付金额

        refundParam.setReturnFee(Integer.valueOf(sellMoney.multiply(new BigDecimal("100")).stripTrailingZeros().toPlainString())); //退款金额

        refundParam.setOutTradeNo(order.getOrderNumber()); //订单编号

        WxConfigVo wxConfigVo = WxConfigApplicationRunner.wxConfigVoCache.get(order.getStoreId(), false);

        BeanUtil.copyProperties(wxConfigVo, refundParam);

        //调用支付退款的Feign
        boolean flag = wxPayFeign.refund(refundParam);
        if (flag) {
            order.setRefundPayMoney(sellMoney);
            order.setStatus(Order.Status.REFUNDSUCCESS.getCode());
            orderRepository.save(order);
            return "退款成功";
        }
        order.setStatus(Order.Status.REFUNDFAIL.getCode());
        orderRepository.save(order);
        return "退款失败";
    }


    /*
     * @author drj
     * @date 2019-04-10 15:24
     * @Description :返回订单详情
     */
    public CusOrderDetailVo orderDetail(String orderId) {

      //获取餐桌
        Map<String,String> map=deskFeign.getAllDeskName();

        Order order = orderRepository.findOne(orderId);
        //初始化订单信息
        CusOrderDetailVo cusOrderVo = new CusOrderDetailVo();
        BeanUtil.copyProperties(order, cusOrderVo);
        cusOrderVo.setDeskName(map.get(order.getDeskId()));//餐桌名称
        BigDecimal sellMoney = orderItemService.getRepository().summaryMoney(order.getId());//实付金额
        cusOrderVo.setActPayMoney(sellMoney);
        //获取点菜数量
        cusOrderVo.setFoodAmount(orderItemService.getRepository().countFood(order.getId()));
        //获取菜品金额
        cusOrderVo.setSumMoney(orderItemService.getRepository().summaryMoney(order.getId()));
        //获取菜品详情
        List<CusOrderItmeDetailVo> cusOrderItmeVoList = new LinkedList<>();
        List<OrderItem> orderItemList = orderItemService.getRepository().findByOrderIdAndDelFlag(order.getId(), CommonConstant.NORMAL_FLAG);
        for (OrderItem orderItem : orderItemList) {
            CusOrderItmeDetailVo cusOrderItmeVo = new CusOrderItmeDetailVo();
            cusOrderItmeVo.setOrderItemId(orderItem.getId());
            cusOrderItmeVo.setFoodName(orderItem.getName());
            cusOrderItmeVo.setUnitPrice(orderItem.getUnitPrice());
            cusOrderItmeVo.setAmount(orderItem.getAmount());
            cusOrderItmeVo.setStatus(orderItem.getStatus());
            cusOrderItmeVoList.add(cusOrderItmeVo);
        }
        cusOrderVo.setOrderItmeVoList(cusOrderItmeVoList);
        return cusOrderVo;
    }

}